`timescale 1ns/1ps
   
module tb_sm3_top();
   
// Parameters   
parameter CLK_PERIOD = 10; // 100 MHz clock
   
// Test vectors   
parameter [511:0] TEST_MESSAGE = 512'h6162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616636461626364;   
parameter [255:0] EXPECTED_HASH = 256'hdebe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732;
   
// DUT Signals   
reg clk;   
reg rst_n;   
reg [31:0] msg_inpt_d;   
reg [3:0] msg_inpt_vld_byte;   
reg msg_inpt_vld;   
reg msg_inpt_lst;   
wire msg_inpt_rdy;   
wire [255:0] cmprss_otpt_res;   
wire cmprss_otpt_vld;
   
// Test variables   
integer i;   
reg test_pass;   
reg [255:0] received_hash;
   
// Instantiate DUT   
sm3_top dut (
    .clk(clk),
    .rst_n(rst_n),
    .msg_inpt_d(msg_inpt_d),
    .msg_inpt_vld_byte(msg_inpt_vld_byte),
    .msg_inpt_vld(msg_inpt_vld),
    .msg_inpt_lst(msg_inpt_lst),
    .msg_inpt_rdy(msg_inpt_rdy),
    .cmprss_otpt_res(cmprss_otpt_res),
    .cmprss_otpt_vld(cmprss_otpt_vld)   
);
   
// Clock generation   
initial begin
    clk = 1'b0;
    forever #(CLK_PERIOD/2) clk = ~clk;   
end
   
// Reset generation   
initial begin
    rst_n = 1'b0;
    #100 rst_n = 1'b1;   
end
   
// Main test sequence   
initial begin
    // Initialize
    test_pass = 1'b1;
    msg_inpt_d = 32'h0;
    msg_inpt_vld_byte = 4'h0;
    msg_inpt_vld = 1'b0;
    msg_inpt_lst = 1'b0;
    
    // Wait for reset to complete
    wait(rst_n == 1'b1);
    @(posedge clk);
    
    // Wait for module to be ready
    wait(msg_inpt_rdy == 1'b1);
    @(posedge clk);
    
    // Send complete 512-bit message in 32-bit chunks (16 transfers)
    for (i = 0; i < 16; i = i + 1) begin
        msg_inpt_d = TEST_MESSAGE[511-i*32 -:32]; // Big-endian transfer
        msg_inpt_vld_byte = 4'hf; // All bytes valid
        msg_inpt_vld = (i == 15) ? 1'b1 : 1'b0; // Last transfer flag
        msg_inpt_lst = 1'b0;
        @(posedge clk);
    end
    
    // Clear inputs after transfer
    msg_inpt_d = 32'h0;
    msg_inpt_vld_byte = 4'h0;
    msg_inpt_vld = 1'b0;
    msg_inpt_lst = 1'b0;
    
    // Wait for output to be valid
    wait(cmprss_otpt_vld == 1'b1);
    @(posedge clk);
    
    // Capture and check the result
    received_hash = cmprss_otpt_res;
    if (received_hash !== EXPECTED_HASH) begin
        test_pass = 1'b0;
        $display("ERROR: Hash mismatch!");
        $display("Expected: %64h", EXPECTED_HASH);
        $display("Received: %64h", received_hash);
    end else begin
        $display("SUCCESS: Hash matches expected value!");
        $display("Hash: %64h", received_hash);
    end
    
    // Finish simulation
    #100;
    if (test_pass) begin
        $display("TEST PASSED");
    end else begin
        $display("TEST FAILED");
    end
    $finish;   
end
   
// Monitor outputs   
initial begin
    $monitor("At time %t: msg_inpt_rdy=%b, cmprss_otpt_vld=%b, hash=%64h",
             $time, msg_inpt_rdy, cmprss_otpt_vld, cmprss_otpt_res);   
end
   
endmodule
